/*
 * ReceiptChecker.cpp
 *
 *  Created on: 2014. 1. 23.
 *      Author: mega
 */

#include "ReceiptChecker.h"
#include <Database/Static.h>
#include <Validator/Static.h>
#include <Dispatcher/Static.h>

namespace ProjectZ { namespace NProcess {

ReceiptChecker::ReceiptChecker() : _clsThreadPool(2)
{

}

ReceiptChecker::~ReceiptChecker()
{

}

void
ReceiptChecker::Push(Param & param)
{
	{
		std::lock_guard<std::mutex> lock(_mutex);
		_clsParamVector.push_back(param);
	}
	_clsThreadPool.PostTask(std::bind(&ReceiptChecker::work, this));
}

void
ReceiptChecker::work()
{
	Param param;

	while (true)
	{
		{
			std::lock_guard<std::mutex> lock(_mutex);
			if (_clsParamVector.size() <= 0 )
				break;

			param = _clsParamVector.front();
			_clsParamVector.pop_front();
		}

		int status = FAIL;
		int curl_status = RECEIPT_FAIL;
		int validator_status = RECEIPT_FAIL;

		if (1 == param._result)
		{
			// 영수증 확인
			::Validator::Command *pCommand = ::Validator::GETCOMMANDPOOL()->NEW();

			if (param._marketType == 0)	// Google
			{
				DEBUGLOG("ReceiptCheck : marketType Google");
				pCommand->SetType(::Validator::Command::E_Type::GOOGLE);
				pCommand->SetPurchaseData(param._purchase.c_str());
				pCommand->SetSignature(param._signature.c_str());

				::Validator::GETSESSION()->SyncExecute(pCommand);

				validator_status = pCommand->GetStatus();
				curl_status = pCommand->GetResult();

				PROCESSLOG("ReceiptCheck : CURL_RESULT=%d, VALIDATOR_RESULT=%d", curl_status, validator_status);

	//			if (1 == curl_status && 0 == validator_status && (0 == errCode || 7 == errCode) )
				if (1 == curl_status && 0 == validator_status)
				{
					status = SUCCESS;		// 성공
				}
				else
				{
					status = RECEIPT_FAIL;	// 실패
				}

				::Validator::GETCOMMANDPOOL()->DEL(pCommand);
			}
			else if (param._marketType == 1)	// IOS
			{
				PROCESSLOG("ReceiptCheck : marketType IOS");
				pCommand->SetType(::Validator::Command::E_Type::IOS);
				pCommand->SetReceiptData(const_cast<char*>(param._purchase.c_str()));

				::Validator::GETSESSION()->SyncExecute(pCommand);

				validator_status = pCommand->GetStatus();
				curl_status = pCommand->GetResult();

				// SandBox 계정인 경우 SandBox서버에 확인 요청
				if (0 == curl_status && 21007 == validator_status)
				{
					if (true == ::ProjectZ::Config::Instance().GetResourceDatabase()._isTest)
					{
						PROCESSLOG("ReceiptCheck : marketType IOS_TEST");
						pCommand->SetType(::Validator::Command::E_Type::IOS_TEST);
						pCommand->SetReceiptData(const_cast<char*>(param._purchase.c_str()));

						::Validator::GETSESSION()->SyncExecute(pCommand);

						validator_status = pCommand->GetStatus();
						curl_status = pCommand->GetResult();
					}
				}

				PROCESSLOG("ReceiptCheck : CURL_RESULT=%d, VALIDATOR_RESULT=%d", curl_status, validator_status);

				if (0 == curl_status && 0 == validator_status)
				{
					status = SUCCESS;		// 성공
				}
				else
				{
					status = RECEIPT_FAIL;	// 실패
				}

				::Validator::GETCOMMANDPOOL()->DEL(pCommand);
			}
			else if (param._marketType == 2)	// Emulator
			{
				if (true == ::ProjectZ::Config::Instance().GetResourceDatabase()._isTest)
				{
					status = SUCCESS;
//					sleep(20);
				}
			}
		}


		// 아이템 구매 상태 갱신
		{
			::Database::Command::Auto clsAuto(::Database::GETCOMMANDPOOL());
			clsAuto->SetQueryType(::Database::Command::S_PROCEDURE);
			clsAuto->MakeQuery("call sp_update_BuyItemData(%d,'%s',%d,%d)", param._recvUserSeq, param._orderID.c_str(), status, param._buySeq);

			if (false == ::Database::GETSESSION()->SyncExecute(1, clsAuto))
			{
				PROCESSLOG("ReceiptCheck : false == ::Database::GETSESSION()->SyncExecute(1, clsAuto)");
				OnEvent(param, ACK_DB_ERROR, validator_status);
				continue;
			}

			if( clsAuto->GetErrorIdx() != 0 )
			{
				PROCESSLOG("ReceiptCheck : clsAuto->GetErrorIdx() != 0");
				OnEvent(param, ACK_DB_ERROR, validator_status);
				continue;
			}
		}

		// 아이템 구매 실패 히스토리 저장
		if (status != SUCCESS)
		{
			PROCESSLOG("ReceiptCheck : status is not SUCCESS!! (%d)", status);

			::Database::Command::Auto clsAuto(::Database::GETCOMMANDPOOL());
			clsAuto->SetQueryType(::Database::Command::S_PROCEDURE);
			clsAuto->MakeQuery("call sp_insert_BuyItemFailData(%d,%d,%d,%d,%d)",
					param._errorCode, param._subErrorCode, param._buySeq, curl_status, validator_status);

			if (false == ::Database::GETSESSION()->SyncExecute(1, clsAuto))
			{
				PROCESSLOG("ReceiptCheck : false == ::Database::GETSESSION()->SyncExecute");
				OnEvent(param, ACK_DB_ERROR, validator_status);
				continue;
			}

			if( clsAuto->GetErrorIdx() != 0 )
			{
				PROCESSLOG("ReceiptCheck : clsAuto->GetErrorIdx() != 0");
				OnEvent(param, ACK_DB_ERROR, validator_status);
				continue;
			}

			OnEvent(param, ACK_RECEIPT_FAILE, validator_status);

			continue;
		}

		OnEvent(param, ACK_OK, validator_status);
	}
}

void
ReceiptChecker::OnEvent(Param & param, int ack, int validatorStatus)
{
	::Dispatcher::Handler::ReceiptCheckWrapper::Data clsReceiptData;
	clsReceiptData._ack			= ack;
	clsReceiptData._buySeq		= param._buySeq;
	clsReceiptData._isGift		= param._isGift;
	clsReceiptData._recvUserSeq	= param._recvUserSeq;
	clsReceiptData._tid			= param._tid;
	clsReceiptData._marketType	= param._marketType;
	clsReceiptData._validatorStatus = validatorStatus;


	param._user->SetReceiptCheckData(clsReceiptData);

	::Dispatcher::Static::InstancePtr()->GetHandler()->OnReceiptCheckFromServer(param._user);
}

} /*NProcess*/ } /*ProjectZ*/
